# @rspress/plugin-preview <SourceCode href="https://github.com/web-infra-dev/rspress/tree/main/packages/plugin-preview" />

import { SourceCode, PackageManagerTabs } from '@rspress/core/theme';

用于预览 md(x) 文件代码块中的组件。

## 安装

<PackageManagerTabs command="add @rspress/plugin-preview -D" />

## 使用

### 引入插件

首先在配置文件中写入以下的配置：

```ts title="rspress.config.ts"
import { defineConfig } from '@rspress/core';
import { pluginPreview } from '@rspress/plugin-preview';

export default defineConfig({
  plugins: [pluginPreview()],
});
```

:::warning 注意
此插件会将 `markdown.mdxRs` 配置为 `false`，未来 Rspress 团队会将该插件移植到 Rust 版本的编译器中。
:::

### 内部组件

内部组件的组件代码声明在 mdx 文件内。你可以在 mdx 文件中声明如下的代码块：

````md
```tsx
function App() {
  return <div>Hello World</div>;
}

export default App;
```
````

值得注意的是，你需要将组件作为 default 导出，Rspress 会自动渲染这个组件。

但是如果你想保留代码块的样式，而不是将其作为组件渲染，你可以添加 `pure` 标识符来指定，使用方式如下：

````md
```tsx pure
function App() {
  return <div>Hello World</div>;
}
export default App;
```
````

如果你配置了 `defaultRenderMode` 为 `'pure'`，那么默认情况下，Rspress 将不会渲染这个组件，而是将其作为代码块来渲染。这种情况下，如果需要将某个代码块渲染为组件，可以通过添加 `preview` 标识符来指定，使用方式如下：

````md
```tsx preview
function App() {
  return <div>Hello World</div>;
}
export default App;
```
````

:::tip 提示
需要保证文档为 `.mdx` 结尾的文件。
:::

### 外部组件

除了将组件代码写在 mdx 文件的代码块中，你还可以将组件代码写在外部文件中，然后在 mdx 文件中通过 `file="./filename"` 的 meta 标记引入。比如

````md title="example.mdx"
```tsx file="./Demo.tsx"

```
````

```tsx title="Demo.tsx"
export default function App() {
  return <div>Hello World</div>;
}
```

外部组件中同样需要将组件作为 default 导出。而通过 code 标签的 src 属性，你可以指定外部组件的路径，该插件同时支持相对路径以及别名路径(alias)。

对于某些比较复杂的组件，这种外部组件的使用方式会更加方便。

## 配置

这个插件接受一个对象参数，类型如下:

```ts
interface PreviewOptions {
  previewMode?: 'internal' | 'iframe';
  iframeOptions?: IframeOptions;
  defaultRenderMode?: 'pure' | 'preview';
}

interface IframeOptions {
  framework?: 'react' | 'solid';
  position?: 'fixed' | 'follow';
  devPort?: number;
}
```

### defaultRenderMode

支持用户配置没有主动声明 `pure` 或 `preview` 标识符的内部代码块的默认行为，默认为 `preview`。

- `pure`: 渲染为普通代码块
- `preview`: 渲染为预览组件

### previewMode

`previewMode` 参数用于指定预览组件是否内置，默认为 `internal`。默认内置模式的展示效果如下：

![](https://lf3-static.bytednsdoc.com/obj/eden-cn/uhbfnupenuhf/rspress/demo-preview-pc.jpeg)

你也可以针对单个代码块设置，例如

````md title="example.mdx"
```tsx file="./Demo.tsx" iframe

```
````

````md title="example.mdx"
```tsx iframe
function App() {
  return <div>Hello World</div>;
}
export default App;
```
````

如果使用 iframe 预览模式，还有以下配置：

### iframeOptions.position

在 iframe 预览模式下时，你可以通过 `position` 参数来决定预览区 iframe 的位置，是跟随页面滚动(`follow` 模式)还是固定在页面中(`fixed` 模式)，默认为 `follow`。

`follow` 模式效果如下：

![](https://lf3-static.bytednsdoc.com/obj/eden-cn/uhbfnupenuhf/rspress/demo-preview-mobile-follow.png)

`fixed` 模式效果如下：

![](https://lf3-static.bytednsdoc.com/obj/eden-cn/uhbfnupenuhf/rspress/demo-preview-mobile-fixed.png)

### iframeOptions.framework

在 iframe 预览模式下，你可以选择渲染框架，目前支持 `react` 和 `solid`。

### iframeOptions.devPort

在 iframe 预览模式下，你可以配置预览组件的 dev server port。

### iframeOptions.builderConfig

配置 iframe 的构建配置，例如添加一些全局代码逻辑。

### iframeOptions.customEntry

配置自定义入口支持其他 `Web` 框架，例如 `Vue`。

仅设置 `iframeOptions.position = follow` 时可使用 customEntry。

```ts
import { defineConfig } from '@rspress/core';
import { pluginPreview } from '@rspress/plugin-preview';
import { pluginVue } from '@rsbuild/plugin-vue';

export default defineConfig({
  // ...
  plugins: [
    pluginPreview({
      previewMode: 'iframe',
      previewLanguages: ['vue'],
      iframeOptions: {
        position: 'follow',
        customEntry: ({ entryCssPath, demoPath }) => {
          return `
          import { createApp } from 'vue';
          import App from ${JSON.stringify(demoPath)};
          import ${JSON.stringify(entryCssPath)};
          createApp(App).mount('#root');
          `;
        },
        builderConfig: {
          plugins: [pluginVue()],
        },
      },
    }),
  ],
});
```

### deprecated: isMobile

从 1.12.0 版本开始，请使用 [previewMode](#previewmode) 配置预览模式。

### deprecated: iframePosition

从 1.12.0 版本开始，请使用 [iframeOptions.position](#iframeoptionsposition)。

### previewLanguages

- Type: `string[]`
- Default: `['jsx', 'tsx']`

支持预览的代码语言，默认支持 jsx 和 tsx 代码。如果你需要支持其它格式的代码，如 json/yaml, 可以配合下面的 `previewCodeTransform` 配置一起使用。

### previewCodeTransform

- Type: `(codeInfo: { language: string; code: string }) => string`
- default: `({ code }) => code`

预览前对代码进行自定义的转换。以 JSON 代码为例，如果你想要通过自定义的转换逻辑渲染一段 JSON Schema：

```json
{
  "type": "div",
  "children": "Render from JSON"
}
```

可以做如下配置：

```ts
pluginPreview({
  // 注意添加默认的 jsx 和 tsx
  previewLanguages: ['jsx', 'tsx', 'json'],
  previewCodeTransform(codeInfo) {
    if (codeInfo.language === 'json') {
      return `
import React from 'react';

const json = ${codeInfo.code};

export default function() {
return React.createElement(json.type, null, json.children);
}
`;
    } else {
      return codeInfo.code;
    }
  },
});
```

这样，最后会渲染出自定义逻辑转换后的组件代码。

:::warning 注意

`previewLanguages` 和 `previewCodeTransform` 配置仅对内部组件生效，即对声明在 mdx 文件中的代码块生效，而对于 `code` 标签中声明的外部文件不会生效！

:::
